home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 7 / BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso / Files / Tele / Pete Johnson / TExport 2.0<source>.cpt / TExport.p < prev    next >
Text File  |  1991-08-05  |  33KB  |  1,014 lines

  1. program TExport (input, output);
  2.  
  3. {     Written by Pete Johnson for the    Glassell Park BBS                }
  4.  
  5. {    Version 2.0 (remember to change VERSION constant!)                }
  6.  
  7. {    Date of last revision: June 26, 1991                            }
  8.  
  9. {    As of version 1.3, TExport no longer uses LSP calls for files        }
  10. {    Version 1.31 is a bug fix release                                }
  11. {    Version 1.32 adds origin line to locally entered Private NetMail        }
  12. {    Version 1.4 adds high message "Look Up" and "Next Launch"            }
  13. {    buttons to Config dialog                                        }
  14.  
  15. {    10/28/89     Now check AREAFIX requests & omit origin lines            }
  16. {            Version 1.5 adds WaitNextEvent for MF compatibility        }
  17. {    11/29/89    Version 1.6 handles point ^A lines                        }
  18. {    5/6/90    Version 1.7 adds configuration for private                }
  19. {                    Origin line                                }
  20. {    6/14/90    Version 1.8 uses Tabby processed flag instead of            }
  21. {                    high message number to locate place            }
  22. {    7/15/90    Version 1.9 speeds up processing by setting                 }
  23. {                    processed flag on all messages                }
  24. {    11/15/90    Version 1.91 has Normal setting for regular                }
  25. {                    processing; otherwise it does a complete scan    }
  26. {    1/8/91    Version 1.92 adds TEXT type option field and Version        }
  27. {                    info in running dialog.                        }
  28. {    2/6/91    Version 1.93 correctly processes 'McNames'.                }
  29. {    5/26/91    Version 1.94 adds WaitNextEvent calls &                    }
  30. {                    SIZE resource.                                }
  31. {    6/19/91    Version 1.95 adds ASCII filter & Squelch Twits features    }
  32. {                    plus export totals for individual sections.        }
  33. {    6/27/91    Version 2.0 cleans up Tabby Log reporting, adds color icons.}
  34.  
  35. {    This program exports messages to Tabby 2.0 using the Generic        }
  36. {    Tabby Message Format.                                        }
  37.  
  38.     uses
  39.         Globals, HelloTabby, HostFile;
  40.  
  41.     const
  42.         VERSION = '2.0';
  43.         TabbyFlag = 64;
  44.  
  45.     type
  46.         DateTimeRecord = packed array[1..6] of char;
  47.  
  48.         Header = record
  49.                 Status: packed array[1..2] of Byte;    {    use Status[1]    }
  50.                 MsgNo: longint;
  51.                 Section: packed array[1..2] of Byte;    {    use Section[1]    }
  52.                 TimeRcvd: DateTimeRecord;
  53.                 MsgFrom: string[31];
  54.                 MsgTo: string[31];
  55.                 MsgSubject: string[41];
  56.                 Destination: packed array[1..68] of char;
  57.                 BeginText: longint;
  58.                 LengthText: longint;
  59.                 ReplyTo: longint;
  60.                 TimeSent: DateTimeRecord
  61.             end;
  62.         MessageSectName = array[1..255] of string[25];
  63.         MSectPtr = ^MessageSectName;
  64.  
  65.     var
  66.         MNamePtr: MSectPtr;
  67.         TLogRef, GenericRef, Unknown: integer;
  68.         Echoes, PrivNet: packed array[1..255] of boolean;
  69.         Ms, TempString, SectionString, TheFileName, GenericPath, TheExportFile: STR255;
  70.         Security, Modifier, Restriction, SectionType, MsgCount: integer;
  71.         WhenRcvdString: DateTimeRecord;
  72.         DialogPointer: DialogPtr;
  73.         DeleteFlag, DeCapitalize, PrivOrigin, Normal: boolean;
  74.         TheRect: rect;
  75.         LastHiMsg, logicalEOF, CharsToSend: longint;
  76.  
  77. {-----------------------------------------------------------------    }
  78.  
  79.     function Wr (FileRefNum: integer; TheMessage: string): OSErr;
  80.  
  81. { Function writes string to text file, returns error code           }
  82.  
  83.         var
  84.             TheLength: longint;
  85.  
  86.     begin
  87.         TheLength := length(TheMessage);
  88.         Wr := FSWrite(FileRefNum, TheLength, Pointer(ord(@TheMessage) + 1));
  89.     end;
  90.  
  91. {-----------------------------------------------------------------    }
  92.  
  93.     function WrLn (FileRefNum: integer; TheMessage: string): OSErr;
  94.  
  95.     begin
  96.         WrLn := Wr(FileRefNum, concat(TheMessage, ENDLINE))
  97.     end;
  98.  
  99. {-----------------------------------------------------------------    }
  100.  
  101.     procedure DeCap (var TheName: str255);
  102.  
  103.         var
  104.             NameCount: integer;
  105.  
  106.         procedure HandleMcName (var McN: str255);    {Adjusts caps in names such as McNamara}
  107.  
  108.             var
  109.                 i: integer;
  110.  
  111.         begin
  112.             if (length(McN) > 2) then
  113.                 for i := 3 to length(McN) do
  114.                     if ((McN[i - 1] = 'c') & (McN[i - 2] = 'M') & (McN[i] in ['a'..'z'])) & ((i = 3) | (McN[i - 3] = ' ')) then
  115.                         McN[i] := chr(ord(McN[i]) - 32);
  116.         end;
  117.  
  118.     begin
  119.         UprString(TheName, false);
  120.         for NameCount := 2 to length(TheName) do        {    Convert name to caps & lower case    }
  121.             if (TheName[NameCount]) in ['A'..'Z'] then
  122.                 if (TheName[NameCount - 1] in ['A'..'Z', 'a'..'z']) then
  123.                     TheName[NameCount] := chr(ord(TheName[NameCount]) + 32);
  124.  
  125.         HandleMcName(TheName)
  126.     end;
  127.  
  128. {-----------------------------------------------------------------    }
  129.  
  130.     procedure FilterToASCII (var MsgTxtString: str255);
  131.  
  132.         var
  133.             charCount: integer;
  134.  
  135.     begin
  136.         for charCount := 1 to length(MsgTxtString) do
  137.             case MsgTxtString[charCount] of
  138.                 '’', '‘': 
  139.                     MsgTxtString[charCount] := '''';
  140.                 '“', '”': 
  141.                     MsgTxtString[charCount] := '"';
  142.                 '—', '…': 
  143.                     MsgTxtString[charCount] := '-';
  144.                 '•': 
  145.                     MsgTxtString[charCount] := '*';
  146.                 '™': 
  147.                     MsgTxtString[charCount] := 't';
  148.                 '©': 
  149.                     MsgTxtString[charCount] := 'c';
  150.                 '®': 
  151.                     MsgTxtString[charCount] := 'r';
  152.                 'ü': 
  153.                     MsgTxtString[charCount] := 'u';
  154.                 'é': 
  155.                     MsgTxtString[charCount] := 'e';
  156.                 'è': 
  157.                     MsgTxtString[charCount] := 'e';
  158.                 otherwise
  159.                     if ord(MsgTxtString[charCount]) > 127 then
  160.                         MsgTxtString[charCount] := '.'
  161.             end
  162.     end;
  163.  
  164. {-----------------------------------------------------------------    }
  165.  
  166.     function Int2Char (Number: integer): char;
  167.  
  168. { Function changes integer to character.                                }
  169.  
  170.     begin
  171.         Int2Char := chr(Number + ord('0'));
  172.     end;
  173.  
  174. { ------------------------------------------------------ }
  175.  
  176.     function TwoDigit (Number: integer): string;
  177.  
  178. { Function changes two-digit number to a two-character string.           }
  179.  
  180.     begin
  181.         TwoDigit := concat(Int2Char(Number div 10), Int2Char(Number mod 10));
  182.     end;
  183.  
  184. { ------------------------------------------------------ }
  185.  
  186.     procedure TimeStamp;
  187.  
  188.         var
  189.             Today: DateTimeRec;
  190.             ASCIIHour: string;
  191.  
  192.     begin
  193.         GetTime(Today);
  194.  
  195. { The TwoDigit function in the following section turns a two-digit integer          }
  196. { into a two-character string. If there are fewer than two digits, the string    }
  197. { contains a leading '0'.                                                                              }
  198.  
  199.         ASCIIHour := TwoDigit(Today.Hour);                {    This bit of nonsense is to get the Tabby Log output        }
  200.         if length(ASCIIHour) > 1 then                    {    to match a Tabby convention: single-digit hours do        }
  201.             if (copy(ASCIIHour, 1, 1) = '0') then        {    not have leading zeroes, even though all other single        }
  202.                 ASCIIHour := copy(ASCIIHour, 2, 1);        {    digit numbers do.                                                }
  203.  
  204.         DateString := concat(TwoDigit(Today.Month), '/', TwoDigit(Today.Day), '/', TwoDigit(Today.Year - 1900));
  205.         TimeString := concat(ASCIIHour, ':', TwoDigit(Today.Minute), ':', TwoDigit(Today.Second));
  206.         DateString := concat(DateString, ' ', TimeString, ' ')
  207.     end;
  208.  
  209. { ------------------------------------------------------ }
  210.  
  211.     function MakeTime (Index: integer; Separator: char): string;
  212.  
  213. { Function changes three chars of DateTimeRecord to formatted time or date string    }
  214.  
  215.         var
  216.             MakeTimeString, LocalTemp: STR255;
  217.  
  218.     begin
  219.         LocalTemp := '';
  220.         NumToString(ord(WhenRcvdString[Index + 1]), LocalTemp);
  221.         if length(LocalTemp) = 1 then
  222.             LocalTemp := concat('0', LocalTemp);
  223.         MakeTimeString := concat(LocalTemp, Separator);
  224.         NumToString(ord(WhenRcvdString[Index + 2]), LocalTemp);
  225.         if length(LocalTemp) = 1 then
  226.             LocalTemp := concat('0', LocalTemp);
  227.         MakeTimeString := concat(MakeTimeString, LocalTemp, Separator);
  228.         NumToString(ord(WhenRcvdString[Index + 3]), LocalTemp);
  229.         if length(LocalTemp) = 1 then
  230.             LocalTemp := concat('0', LocalTemp);
  231.         MakeTime := concat(MakeTimeString, LocalTemp)
  232.     end;
  233.  
  234. {-----------------------------------------------------------------    }
  235.  
  236.     function Make2Digits (ConvertFrom: string): integer;
  237.  
  238. {    Converts two-character string into an ascii value        }
  239.  
  240.         var
  241.             Num1, Num2: integer;
  242.  
  243.     begin
  244.         Num1 := ord(ConvertFrom[1]) - ord('0');
  245.         Num2 := ord(ConvertFrom[2]) - ord('0');
  246.         Make2Digits := Num2 + (Num1 * 10)
  247.     end;
  248.  
  249. { ------------------------------------------------------ }
  250.  
  251.     function GetWidth (number: integer): integer;
  252.  
  253.     begin
  254.         if number > 999 then
  255.             GetWidth := 4
  256.         else if number > 99 then
  257.             GetWidth := 3
  258.         else if number > 9 then
  259.             GetWidth := 2
  260.         else
  261.             GetWidth := 1
  262.     end;
  263.  
  264. { ------------------------------------------------------ }
  265.  
  266.     procedure TReadMESSAGES;
  267.  
  268. { Procedure reads the MESSAGES file                                }
  269.  
  270.         var
  271.             MSCount, MSGRefNum: integer;
  272.             MSChar, OneChar: char;
  273.             SectionName, MsgString: STR255;
  274.             CharsToSend: longint;
  275.             MsgByte: Byte;
  276.  
  277.     begin
  278.         MNamePtr := MSectPtr(NewPtr(SizeOf(MessageSectName)));
  279.         MsgPath := '';
  280.         CharsToSend := 255;
  281.         Err := FSOpen(MESSAGESPath, vRefNum, MSGRefNum);
  282.         Err := FSRead(MSGRefNum, CharsToSend, @MsgString);
  283.         MsgPath := concat(MsgString, ':');
  284.  
  285.         CharsToSend := 4;
  286.         Err := SetFPos(MSGRefNum, fsFromStart, 50);
  287.         Err := FSRead(MSGRefNum, CharsToSend, @LowMsg);
  288.         Err := FSRead(MSGRefNum, CharsToSend, @HiMsg);
  289.         Err := FSRead(MSGRefNum, CharsToSend, @MSGTXTLength);
  290.  
  291.         Unknown := 255;
  292.         for MSCount := 1 to 254 do
  293.             begin
  294.                 if Unknown = 255 then
  295.                     begin
  296.                         if MultiFinder & ((MSCount mod 25) = 0) then
  297.                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  298.                         Err := SetFPos(MSGRefNum, fsFromStart, (62 + (MSCount - 1) * 36));
  299.                         CharsToSend := 255;
  300.                         Err := FSRead(MSGRefNum, CharsToSend, @MsgString);
  301.                         MNamePtr^[MSCount] := MsgString;
  302.                         SectionName := MsgString;
  303.                         UprString(SectionName, false);
  304.                         if SectionName = 'UNKNOWN' then
  305.                             Unknown := MSCount;
  306.                     end;    {    if Unknown = 255    }
  307.  
  308.                 Err := SetFPos(MSGRefNum, fsFromStart, (97 + (MSCount - 1) * 36));
  309.                 CharsToSend := 1;
  310.                 Err := FSRead(MSGRefNum, CharsToSend, @MsgByte);
  311.  
  312.                 MsgByte := MsgByte div 256;
  313.  
  314.                 Echoes[MSCount] := false;
  315.                 PrivNet[MSCount] := false;
  316.  
  317.                 case MsgByte of
  318.  
  319.                     4: 
  320.                         Echoes[MSCount] := true;
  321.  
  322.                     3: 
  323.                         PrivNet[MSCount] := true;
  324.  
  325.                     otherwise
  326.                         ;
  327.  
  328.                 end;    {    case statement    }
  329.  
  330.             end;        {    for MSCount := 1 to 255 do    }
  331.  
  332.         Err := FSClose(MSGRefNum);
  333.  
  334.     end;
  335.  
  336. { ------------------------------------------------------ }
  337.  
  338.     procedure ProcessMSGHDR;
  339.  
  340. { Procedure processes MSGHDR file and MSGTXT file                                }
  341.  
  342.         const
  343.             MaxBadNames = 100;
  344.  
  345.         var
  346.             ThisHeader: Header;
  347.             FlagCount, Count1, Count2, Count3, TextLineLength, DestCount, DestLimit, TConfigRef, StringEnd: integer;
  348.             MHdrRef, MTextRef, AreaRef, Counter, PeriodMark: integer;
  349.             HeaderEnd, Position, MSGTXTPos, PlaceMark, Index, HeaderSize: longint;
  350.             TheDestination, ReplyMark, MsgTxtString, OriginLine, LocationLine, PointID: STR255;
  351.             Adjustment: real;
  352.             TextLine: packed array[1..255] of char;
  353.             BadNames: array[1..MaxBadNames] of string[15];
  354.             ThisPub, ThisPriv, Marker, Range, GenExpRef: integer;
  355.  
  356.         procedure FindMHPosition;
  357.  
  358.             var
  359.                 HiBound, LoBound: longint;
  360.  
  361. { Procedure finds correct position in MSGHDR file                    }
  362.  
  363.         begin
  364.             if MultiFinder then
  365.                 IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  366.             HiBound := (HeaderEnd div sizeOf(ThisHeader)) - 1;    {    ...mark start of last record                }
  367.             Range := HiBound;
  368.             LoBound := 0;
  369.             if Normal then        {normal operation looks for last message processed    }
  370.                 begin
  371.                     repeat
  372.                         Position := (LoBound + HiBound) div 2;
  373.                         Err := SetFPos(MHdrRef, fsFromStart, Position * HeaderSize);
  374.                         Err := FSRead(MHdrRef, HeaderSize, @ThisHeader);
  375.                         if (BitAnd(TabbyFlag, ThisHeader.Status[1]) = TabbyFlag) then    {processed for Tabby}
  376.                             LoBound := succ(Position)
  377.                         else
  378.                             HiBound := pred(Position)
  379.                     until (LoBound >= HiBound) | (Err <> NoErr);
  380.                     while (Position > 1) & (BitAnd(TabbyFlag, ThisHeader.Status[1]) <> TabbyFlag) & (Err = NoErr) do
  381.                         begin
  382.                             Position := pred(Position);
  383.                             Err := SetFPos(MHdrRef, fsFromStart, Position * HeaderSize);
  384.                             Err := FSRead(MHdrRef, HeaderSize, @ThisHeader);
  385.                         end
  386.                 end
  387.             else
  388.                 Position := 0;        {if not normal, begin at the start}
  389.             Err := SetFPos(MHdrRef, fsFromStart, Position * HeaderSize);
  390.             Range := Range - Position;
  391.             if Range < 1 then
  392.                 Range := 1;
  393.             if MultiFinder then
  394.                 IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  395.         end;        {    procedure FindMHPosition    }
  396.  
  397.         var
  398.             BadNameFile, HowManyBadNames, ArrayCount: integer;
  399.             goodUser, goodExport: boolean;
  400.             firstName, lastName: str255;
  401.             ThisSection, ThisStatus: Byte;
  402.             Flag: packed array[1..3] of char;
  403.             ExportArray: array[1..255] of integer;
  404.  
  405.     begin
  406.         if MultiFinder then
  407.             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  408.         Marker := 0;
  409.         OriginLine := '';
  410.         for ArrayCount := 1 to 255 do
  411.             ExportArray[ArrayCount] := 0;
  412.  
  413.         for Counter := 1 to MaxBadNames do
  414.             BadNames[Counter] := '';
  415.         Err := FSOpen(concat(gDefaultPath, 'Bad User Names'), vRefNum, BadNameFile);
  416.         Counter := 1;
  417.         while (Err = NoErr) & (Counter < MaxBadNames + 1) do
  418.             begin
  419.                 Err := ReadALine(BadNameFile, BadNames[Counter]);
  420.                 if BadNames[Counter] = '' then
  421.                     leave;
  422.                 Counter := succ(Counter);
  423.             end;
  424.         HowManyBadNames := Counter - 1;
  425.         Err := FSClose(BadNameFile);
  426.  
  427.         TheExportFile := concat(GenericPath, 'Generic Export');
  428.         MakeTextFile(TheExportFile);
  429.         Err := FSOpen(TheExportFile, vRefNum, GenExpRef);
  430.         Err := SetFPos(GenExpRef, fsFromLEOF, 0);    {    Set file position to logical end of file    }
  431.  
  432.         TheFileName := concat(MsgPath, 'MSGHDR');
  433.         Err := FSOpen(concat(MsgPath, 'MSGHDR'), vRefNum, MHdrRef);
  434.         if Err = noErr then
  435.             begin
  436.                 HeaderSize := sizeOf(ThisHeader);
  437.                 Err := GetEOF(MHdrRef, HeaderEnd);
  438.                 FindMHPosition;
  439.                 Err := GetFPos(MHdrRef, Position);            {    Get current file position            }
  440.                 Range := (HeaderEnd - Position) div sizeOf(ThisHeader);
  441.                 Adjustment := Range / 100;
  442.                 Err := FSOpen(concat(MsgPath, 'MSGTXT'), vRefNum, MTextRef);
  443.                 if Err = noErr then
  444.                     begin
  445.                         while (Position < HeaderEnd) do
  446.                             begin
  447.                                 if MultiFinder then
  448.                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  449.                                 goodUser := true;
  450.                                 goodExport := false;
  451.                                 Marker := Marker + 1;
  452.                                 TheRect.right := trunc((Marker / Adjustment) + 28);
  453.                                 if TheRect.right > 128 then
  454.                                     TheRect.right := 128;
  455.                                 PaintRect(TheRect);
  456.                                 Err := FSRead(MHdrRef, HeaderSize, @ThisHeader);
  457.                                 with ThisHeader do
  458.                                     begin
  459.                                         ThisStatus := Status[1];            {    use 'good' byte    }
  460.                                         ThisSection := Section[1];        {    use 'good' byte    }
  461.                                         if (BitAnd(32, ThisStatus) = 32) then                        {    Local origin        }
  462.                                             if ((Echoes[ThisSection]) | PrivNet[ThisSection]) then        {    Net pub/priv        }
  463.                                                 if (BitAnd(TabbyFlag, ThisStatus) = 0) then                {    Not yet to Tabby    }
  464.                                                     if (BitAnd(1, ThisStatus) = 0) then                    {    Not deleted        }
  465.                                                         if (ThisSection in [1..255]) then                    {    Valid section?        }
  466.                                                             goodExport := true;
  467.  
  468.                                         if goodExport & SilenceTwits then
  469.                                             begin
  470.                                                 firstName := copy(MsgFrom, 1, pos(' ', MsgFrom) - 1);
  471.                                                 lastName := copy(MsgFrom, pos(' ', MsgFrom) + 1, 255);
  472.                                                 for Counter := 1 to HowManyBadNames do
  473.                                                     if EqualString(firstName, BadNames[Counter], false, false) | EqualString(lastName, BadNames[Counter], false, false) then
  474.                                                         begin
  475.                                                             goodUser := false;
  476.                                                             Status[1] := BitOr(1, Status[1]);                    {    Set Delete Bit        }
  477.                                                             Err := FSOpen(concat(gDefaultPath, 'Tabby:Tabby Log'), vRefNum, TLogRef);
  478.                                                             Err := SetFPos(TLogRef, fsFromLEOF, 0);
  479.                                                             TimeStamp;
  480.                                                             TempString := concat(DateString, 'TExport - **Deleted** Message from ', MsgFrom);
  481.                                                             Err := WrLn(TLogRef, TempString);
  482.                                                             Err := FSClose(TLogRef);
  483.                                                             leave
  484.                                                         end
  485.                                             end;
  486.  
  487.                                         if goodExport & goodUser then
  488.                                             begin
  489.                                                 MsgCount := succ(MsgCount);
  490.                                                 ExportArray[ThisSection] := succ(ExportArray[ThisSection]);
  491.                                                 Flag[1] := ' ';
  492.                                                 if (Echoes[ThisSection]) then
  493.                                                     Flag[2] := 'E'
  494.                                                 else
  495.                                                     begin
  496.                                                         Flag[2] := 'M';
  497.                                                         if DeleteFlag then
  498.                                                             ThisStatus := BitOr(1, ThisStatus)        {Set Delete Bit    }
  499.                                                     end;
  500.                                                 Flag[3] := ' ';
  501.                                                 Status[1] := ThisStatus;                                        {    Restore 'undefined' byte    }
  502.                                                 Err := WrLn(GenExpRef, Flag);
  503.                                                 NumToString(ThisSection, SectionString);
  504.                                                 while (length(SectionString) < 3) do
  505.                                                     SectionString := concat('0', SectionString);
  506.                                                 Err := WrLn(GenExpRef, SectionString);
  507.                                                 WhenRcvdString := TimeRcvd;
  508.                                                 TempString := MakeTime(0, '/');
  509.                                                 Err := WrLn(GenExpRef, TempString);
  510.                                                 TempString := MakeTime(3, ':');
  511.                                                 Err := WrLn(GenExpRef, TempString);
  512.                                                 TheDestination := '';
  513.                                                 PeriodMark := 0;
  514.                                                 if not (Echoes[ThisSection]) then
  515.                                                     begin
  516.                                                         DestLimit := ord(Destination[1]) + 1;
  517.                                                         if DestLimit > 16 then
  518.                                                             DestLimit := 16;
  519.                                                         for DestCount := 2 to DestLimit do
  520.                                                             TheDestination := concat(TheDestination, Destination[DestCount]);
  521.                                                         PeriodMark := pos('.', TheDestination);
  522.                                                         if PeriodMark <> 0 then
  523.                                                             begin
  524.                                                                 PointID := copy(TheDestination, PeriodMark + 1, length(TheDestination) - PeriodMark);
  525.                                                                 TheDestination := copy(TheDestination, 1, PeriodMark - 1);
  526.                                                             end;
  527.                                                     end;
  528.                                                 if MultiFinder then
  529.                                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  530.                                                 Err := WrLn(GenExpRef, TheDestination);
  531.                                                 TempString := MsgFrom;
  532.                                                 DeCap(TempString);
  533.                                                 Err := WrLn(GenExpRef, TempString);
  534.                                                 TempString := MsgTo;
  535.                                                 DeCap(TempString);
  536.                                                 Err := WrLn(GenExpRef, TempString);
  537.                                                 if (BitAnd(2, ThisStatus) = 2) then                {    Message is a reply                            }
  538.                                                     begin
  539.                                                         ReplyMark := copy(MsgSubject, 1, 3);            {    Grab the first three characters of Subject    }
  540.                                                         uprString(ReplyMark, false);
  541.                                                         if (ReplyMark <> 'RE:') then                    {    Subject is not already marked as reply        }
  542.                                                             if length(MsgSubject) < 38 then                {    Subject isn't already too long                }
  543.                                                                 MsgSubject := concat('Re: ', MsgSubject)
  544.                                                     end;
  545.                                                 if MultiFinder then
  546.                                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  547.                                                 Err := WrLn(GenExpRef, MsgSubject);
  548.                                                 if (PeriodMark <> 0) then    {    First line of message text will contain ^ATOPT PointNo    }
  549.                                                     Err := WrLn(GenExpRef, concat(CTLA, 'TOPT ', PointID));
  550.                                                 Err := SetFPos(MTextRef, fsFromStart, BeginText);
  551.                                                 Count1 := 0;
  552.                                                 while Count1 < LengthText do
  553.                                                     begin
  554.                                                         if MultiFinder then
  555.                                                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  556.                                                         Err := GetFPos(MTextRef, MSGTXTPos);            {    Get current MSGTXT file position    }
  557.                                                         if (MSGTXTPos + 255) < MSGTXTLength then
  558.                                                             CharsToSend := 255
  559.                                                         else
  560.                                                             CharsToSend := MSGTXTLength - MSGTXTPos;
  561.                                                         Err := FSRead(MTextRef, CharsToSend, @MsgTxtString);
  562.                                                         Err := SetFPos(MTextRef, fsFromStart, (MSGTXTPos + length(MsgTxtString) + 1));
  563.  
  564.                                                         if (Length(MsgTxtString) < 91) then
  565.                                                             begin
  566.                                                                 if ASCIIFilter then
  567.                                                                     FilterToASCII(MsgTxtString);
  568.                                                                 Err := WrLn(GenExpRef, MsgTxtString);
  569.                                                             end;
  570.                                                         Count1 := Count1 + length(MsgTxtString) + 1;
  571.  
  572.                                                     end;        {    while Count1 < LengthText    }
  573.  
  574.                                                 TempString := MsgTo;
  575.                                                 uprString(TempString, false);
  576.                                                 if PrivNet[ThisSection] & (TempString <> 'AREAFIX') & PrivOrigin then        {    it' s local netmail & not an AREAFIX req -- add origin line }
  577.                                                     begin
  578.                                                         if (OriginLine = '') then
  579.                                                             begin
  580.                                                                 Err := FSOpen(concat(gDefaultPath, 'Tabby:Areas.BBS'), vRefNum, AreaRef);
  581.                                                                 Err := GetEOF(AreaRef, Index);
  582.                                                                 Err := SetFPos(AreaRef, fsFromStart, 0);
  583.                                                                 if Index > 255 then
  584.                                                                     Index := 255;
  585.                                                                 Err := FSRead(AreaRef, Index, @TextLine);
  586.                                                                 Err := FSClose(AreaRef);
  587.                                                                 StringEnd := pos(EndLine, TextLine);
  588.                                                                 if StringEnd < 1 then
  589.                                                                     StringEnd := Index;
  590.                                                                 for Counter := 1 to StringEnd - 1 do
  591.                                                                     OriginLine := concat(OriginLine, TextLine[Counter]);
  592.  
  593.                                                                 LocationLine := ' (';
  594.                                                                 Err := FSOpen(concat(gDefaultPath, 'Tabby:Tabby Config'), vRefNum, TConfigRef);
  595.                                                                 Err := GetEOF(TConfigRef, Index);
  596.                                                                 Err := SetFPos(TConfigRef, fsFromStart, 0);
  597.                                                                 if Index > 255 then
  598.                                                                     Index := 255;
  599.                                                                 Err := FSRead(TConfigRef, Index, @TextLine);
  600.                                                                 Err := FSClose(TConfigRef);
  601.                                                                 StringEnd := pos(EndLine, TextLine);
  602.                                                                 if StringEnd < 1 then
  603.                                                                     StringEnd := Index;
  604.                                                                 for Counter := 1 to StringEnd - 1 do
  605.                                                                     LocationLine := concat(LocationLine, TextLine[Counter]);
  606.                                                                 LocationLine := concat(LocationLine, ')');
  607.                                                                 OriginLine := concat(' * Origin: ', OriginLine, LocationLine);
  608.                                                             end;        {    if OriginLine <> ''    }
  609.  
  610.                                                         if MultiFinder then
  611.                                                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  612.                                                         Err := WrLn(GenExpRef, '   ');
  613.                                                         Err := WrLn(GenExpRef, '---');
  614.                                                         Err := WrLn(GenExpRef, '   ');
  615.                                                         Err := WrLn(GenExpRef, OriginLine);
  616.                                                         Err := WrLn(GenExpRef, '   ');
  617.                                                         if MultiFinder then
  618.                                                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  619.                                                     end;        {    if PrivNet[ThisSection] & (TempString <> 'AREAFIX')    }
  620.                                                 Err := WrLn(GenExpRef, null);
  621.                                             end;    {    if (BitAnd(32, ThisStatus) = 32) etc...        }
  622.                                     end;        {    with ThisHeader do    }
  623.                                 ThisHeader.Status[1] := BitOr(TabbyFlag, ThisHeader.Status[1]);        {    Set Tabby bit    }
  624.                                 Err := SetFPos(MHdrRef, fsFromMark, -HeaderSize);    {    Back up to the start of this record            }
  625.                                 Err := FSWrite(MHdrRef, HeaderSize, @ThisHeader);    {    Write a fresh copy with the Tabby bit set    }
  626.                                 Err := GetFPos(MHdrRef, Position);                {    Get current file position                        }
  627.                             end;        {    while (Position < HeaderEnd)    }
  628.                         TheRect.right := 128;
  629.                         PaintRect(TheRect);
  630.                         Err := FSClose(GenExpRef);
  631.                         Err := FSClose(MHdrRef);
  632.                         Err := FSClose(MTextRef);
  633.                         if SectionCount then
  634.                             begin
  635.                                 TimeStamp;
  636.                                 Err := FSOpen(concat(gDefaultPath, 'Tabby:Tabby Log'), vRefNum, TLogRef);
  637.                                 Err := SetFPos(TLogRef, fsFromLEOF, 0);
  638.                                 for ArrayCount := 1 to 255 do
  639.                                     if ExportArray[ArrayCount] > 0 then
  640.                                         begin
  641.                                             if ExportArray[ArrayCount] = 1 then
  642.                                                 Err := WrLn(TLogRef, concat(DateString, 'TExport - ', StringOf(ExportArray[ArrayCount] : GetWidth(MsgCount)), ' Message from ', MNamePtr^[ArrayCount], ' #', StringOf(ArrayCount : 1)))
  643.                                             else
  644.                                                 Err := WrLn(TLogRef, concat(DateString, 'TExport - ', StringOf(ExportArray[ArrayCount] : GetWidth(MsgCount)), ' Messages from ', MNamePtr^[ArrayCount], ' #', StringOf(ArrayCount : 1)));
  645.                                         end;
  646.                                 Err := FSClose(TLogRef);
  647.                             end;    {if SectionCount}
  648.                     end;        {no error opening MSGTXT}
  649.             end;    {no error opening MSGHDR}
  650.         if MultiFinder then
  651.             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  652.         if MNamePtr <> nil then
  653.             begin
  654.                 DisposPtr(Pointer(MNamePtr));
  655.                 MNamePtr := nil
  656.             end
  657.     end;
  658.  
  659. { ------------------------------------------------------ }
  660.  
  661.     procedure HandleDialog;
  662.  
  663.         var
  664.             theDialog: DialogPtr;
  665.             ItemHit, itemType, whichItem, MsgRefNum: integer;
  666.             itemHandle: Handle;
  667.             dispRect: Rect;
  668.             thisButton: ControlHandle;
  669.             where: point;
  670.             CharsToSend, HiMsgNumber: longint;
  671.             fileReply: SFReply;
  672.             whatToFind: SFTypeList;
  673.             NextLaunch: str255;
  674.  
  675.     begin
  676.         InitCursor;
  677.         theDialog := GetNewDialog(1002, nil, POINTER(-1));
  678.         SetPort(theDialog);
  679.         FrameDItem(theDialog, Ok);
  680.  
  681.         NextLaunch := GetString(500)^^;        {    Get next launch string from resource    }
  682.         getDItem(theDialog, 5, itemType, itemHandle, dispRect);
  683.         SetIText(itemHandle, NextLaunch);
  684.         ;
  685.         getDItem(theDialog, 6, itemType, itemHandle, dispRect);
  686.         thisButton := ControlHandle(itemHandle);
  687.         if DeleteFlag then
  688.             SetCtlValue(thisButton, 1)
  689.         else
  690.             SetCtlValue(thisButton, 0);
  691.         ;
  692.         getDItem(theDialog, 7, itemType, itemHandle, dispRect);
  693.         thisButton := ControlHandle(itemHandle);
  694.         if DeCapitalize then
  695.             SetCtlValue(thisButton, 1)
  696.         else
  697.             SetCtlValue(thisButton, 0);
  698.         ;
  699.         getDItem(theDialog, 8, itemType, itemHandle, dispRect);
  700.         thisButton := ControlHandle(itemHandle);
  701.         if PrivOrigin then
  702.             SetCtlValue(thisButton, 1)
  703.         else
  704.             SetCtlValue(thisButton, 0);
  705.  
  706.         getDItem(theDialog, 15, itemType, itemHandle, dispRect);
  707.         thisButton := ControlHandle(itemHandle);
  708.         if Normal then
  709.             SetCtlValue(thisButton, 1)
  710.         else
  711.             SetCtlValue(thisButton, 0);
  712.  
  713.         getDItem(theDialog, 16, itemType, itemHandle, dispRect);
  714.         SetIText(itemHandle, CreatorType);
  715.  
  716.         getDItem(theDialog, 19, itemType, itemHandle, dispRect);
  717.         thisButton := ControlHandle(itemHandle);
  718.         if ASCIIFilter then
  719.             SetCtlValue(thisButton, 1)
  720.         else
  721.             SetCtlValue(thisButton, 0);
  722.  
  723.         getDItem(theDialog, 20, itemType, itemHandle, dispRect);
  724.         thisButton := ControlHandle(itemHandle);
  725.         if SilenceTwits then
  726.             SetCtlValue(thisButton, 1)
  727.         else
  728.             SetCtlValue(thisButton, 0);
  729.  
  730.         getDItem(theDialog, 21, itemType, itemHandle, dispRect);
  731.         thisButton := ControlHandle(itemHandle);
  732.         if SectionCount then
  733.             SetCtlValue(thisButton, 1)
  734.         else
  735.             SetCtlValue(thisButton, 0);
  736.  
  737.         ForeColor(redColor);
  738.         getDItem(theDialog, 3, itemType, itemHandle, dispRect);
  739.         TempString := concat('TExport v ', VERSION);
  740.         SetIText(itemHandle, TempString);
  741.         ForeColor(blackColor);
  742.         ;
  743.         if StillDown then
  744.             repeat
  745.             until not Button;
  746.         repeat
  747.             ModalDialog(nil, ItemHit);                                            {IM I-415}
  748.             ;
  749.             case ItemHit of
  750.                 1: { OK button hit -- save resources }
  751.                     begin
  752.                         getDItem(theDialog, 5, itemType, itemHandle, dispRect);
  753.                         GetIText(itemHandle, NextLaunch);
  754.                         RmveResource(GetResource('STR ', 500));
  755.                         UpdateResFile(CurResFile);
  756.                         AddResource(Handle(NewString(NextLaunch)), 'STR ', 500, 'Next Launch');
  757.                         ;
  758.                         TempString := 'NNNNNNN';
  759.                         ;
  760.                         if DeleteFlag then
  761.                             TempString[1] := 'Y';
  762.                         ;
  763.                         if DeCapitalize then
  764.                             TempString[2] := 'Y';
  765.                         ;
  766.                         if PrivOrigin then
  767.                             TempString[3] := 'Y';
  768.                         ;
  769.                         if Normal then
  770.                             TempString[4] := 'Y';
  771.  
  772.                         if ASCIIFilter then
  773.                             TempString[5] := 'Y';
  774.  
  775.                         if SilenceTwits then
  776.                             TempString[6] := 'Y';
  777.  
  778.                         if SectionCount then
  779.                             TempString[7] := 'Y';
  780.  
  781.                         RmveResource(GetResource('STR ', 501));
  782.                         UpdateResFile(CurResFile);
  783.                         AddResource(Handle(NewString(TempString)), 'STR ', 501, 'Defaults');
  784.                         ;
  785.                         RmveResource(GetResource('STR ', 503));
  786.                         UpdateResFile(CurResFile);
  787.                         AddResource(Handle(NewString(CreatorType)), 'STR ', 503, 'TEXT Creator');
  788.                         ;
  789.                     end;
  790.  
  791.                 2: 
  792.                     ; { Cancel button hit—do nothing    }
  793.  
  794.                 6: 
  795.                     begin { Delete Sent Netmail switch    }
  796.                         DeleteFlag := not (DeleteFlag);
  797.                         getDItem(theDialog, 6, itemType, itemHandle, dispRect);
  798.                         thisButton := ControlHandle(itemHandle);
  799.                         if DeleteFlag then
  800.                             SetCtlValue(thisButton, 1)
  801.                         else
  802.                             SetCtlValue(thisButton, 0);
  803.                     end;
  804.  
  805.                 7: 
  806.                     begin { DeCapitalize switch    }
  807.                         DeCapitalize := not (DeCapitalize);
  808.                         getDItem(theDialog, 7, itemType, itemHandle, dispRect);
  809.                         thisButton := ControlHandle(itemHandle);
  810.                         if DeCapitalize then
  811.                             SetCtlValue(thisButton, 1)
  812.                         else
  813.                             SetCtlValue(thisButton, 0);
  814.                     end;
  815.  
  816.                 4: 
  817.                     begin { Look Up Next Launch button        }
  818.                         where.h := 60;
  819.                         where.v := 80;
  820.                         whatToFind[0] := 'APPL';
  821.                         ParamText('next application to launch', '', '', '');
  822.                         SFGetFile(where, '', nil, 1, whatToFind, nil, fileReply);
  823.                         if fileReply.good then
  824.                             begin
  825.                                 getDItem(theDialog, 5, itemType, itemHandle, dispRect);
  826.                                 SetIText(itemHandle, fileReply.fName);
  827.                             end;
  828.                         FrameDItem(theDialog, Ok);
  829.                     end;
  830.  
  831.                 8: 
  832.                     begin { Private Origin Line switch    }
  833.                         PrivOrigin := not (PrivOrigin);
  834.                         getDItem(theDialog, 8, itemType, itemHandle, dispRect);
  835.                         thisButton := ControlHandle(itemHandle);
  836.                         if PrivOrigin then
  837.                             SetCtlValue(thisButton, 1)
  838.                         else
  839.                             SetCtlValue(thisButton, 0);
  840.                     end;
  841.  
  842.                 15: 
  843.                     begin { Normal Operation switch    }
  844.                         Normal := not (Normal);
  845.                         getDItem(theDialog, 15, itemType, itemHandle, dispRect);
  846.                         thisButton := ControlHandle(itemHandle);
  847.                         if Normal then
  848.                             SetCtlValue(thisButton, 1)
  849.                         else
  850.                             SetCtlValue(thisButton, 0);
  851.                     end;
  852.  
  853.                 19: 
  854.                     begin { ASCII Filter switch    }
  855.                         ASCIIFilter := not (ASCIIFilter);
  856.                         getDItem(theDialog, 19, itemType, itemHandle, dispRect);
  857.                         thisButton := ControlHandle(itemHandle);
  858.                         if ASCIIFilter then
  859.                             SetCtlValue(thisButton, 1)
  860.                         else
  861.                             SetCtlValue(thisButton, 0);
  862.                     end;
  863.  
  864.                 20: 
  865.                     begin { SilenceTwits switch    }
  866.                         SilenceTwits := not (SilenceTwits);
  867.                         getDItem(theDialog, 20, itemType, itemHandle, dispRect);
  868.                         thisButton := ControlHandle(itemHandle);
  869.                         if SilenceTwits then
  870.                             SetCtlValue(thisButton, 1)
  871.                         else
  872.                             SetCtlValue(thisButton, 0);
  873.                     end;
  874.  
  875.                 21: 
  876.                     begin { SectionCount switch    }
  877.                         SectionCount := not SectionCount;
  878.                         getDItem(theDialog, 21, itemType, itemHandle, dispRect);
  879.                         thisButton := ControlHandle(itemHandle);
  880.                         if SectionCount then
  881.                             SetCtlValue(thisButton, 1)
  882.                         else
  883.                             SetCtlValue(thisButton, 0);
  884.                     end;
  885.  
  886.                 16:  { TEXT Creator field    }
  887.                     begin
  888.                         getDItem(theDialog, ItemHit, itemType, itemHandle, dispRect);
  889.                         GetIText(itemHandle, CreatorType);
  890.                     end;
  891.  
  892.                 otherwise
  893.                     ;    {    do nothing    }
  894.  
  895.             end;
  896.         until (ItemHit = 1) or (ItemHit = 2);
  897.         DisposDialog(theDialog)
  898.     end;
  899.  
  900. { ------------------------------------------------------ }
  901.  
  902.     var
  903.         itemType: integer;
  904.         itemHandle: handle;
  905.         dispRect: rect;
  906.  
  907. begin
  908.     TempString := GetString(501)^^;
  909.     uprString(TempString, false);
  910.  
  911.     if (TempString[1] = 'Y') then
  912.         DeleteFlag := true
  913.     else
  914.         DeleteFlag := false;
  915.  
  916.     if (TempString[2] = 'Y') then
  917.         DeCapitalize := true
  918.     else
  919.         DeCapitalize := false;
  920.  
  921.     if (TempString[3] = 'Y') then
  922.         PrivOrigin := true
  923.     else
  924.         PrivOrigin := false;
  925.  
  926.     if (TempString[4] = 'Y') then
  927.         Normal := true
  928.     else
  929.         Normal := false;
  930.  
  931.     if (TempString[5] = 'Y') then
  932.         ASCIIFilter := true
  933.     else
  934.         ASCIIFilter := false;
  935.  
  936.     if (TempString[6] = 'Y') then
  937.         SilenceTwits := true
  938.     else
  939.         SilenceTwits := false;
  940.  
  941.     if (TempString[7] = 'Y') then
  942.         SectionCount := true
  943.     else
  944.         SectionCount := false;
  945.  
  946.     CreatorType := GetString(503)^^;
  947.     while length(CreatorType) < 4 do
  948.         CreatorType := concat(CreatorType, ' ');
  949.     while length(CreatorType) > 4 do
  950.         CreatorType := copy(CreatorType, 1, length(CreatorType) - 1);
  951.  
  952.     if Button then
  953.         HandleDialog        { If user is holding down the mouse button, reconfigure and end }
  954.     else
  955.         begin
  956.             HelloTabby;    { find out what's next on the launchpad }
  957.             MsgCount := 0;
  958.             Err := GetVol(@gVolName, vRefNum);        { Get volume ref # for default volume }
  959.             DialogPointer := GetNewDialog(1001, nil, POINTER(-1));
  960.             DrawDialog(DialogPointer);
  961.             SetPort(DialogPointer);
  962.             ForeColor(redColor);
  963.             TextFont(Geneva);
  964.             TextSize(9);
  965.             getDItem(DialogPointer, 2, itemType, itemHandle, dispRect);
  966.             SetIText(itemHandle, VERSION);
  967.             SetRect(TheRect, 28, 49, 128, 54);
  968.             FrameRect(TheRect);
  969.             TimeStamp;
  970.             if MultiFinder then
  971.                 IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  972.  
  973.             Err := FSOpen(concat(gDefaultPath, 'Tabby:Tabby Log'), vRefNum, TLogRef);
  974.             Err := SetFPos(TLogRef, fsFromLEOF, 0);
  975.             TempString := concat(DateString, 'TExport - Program Starting (v ', VERSION, ')');
  976.             Err := WrLn(TLogRef, TempString);
  977.             Err := FSClose(TLogRef);
  978.  
  979.             if MultiFinder then
  980.                 IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  981.             Err := FSOpen(concat(gDefaultPath, 'Generic'), vRefNum, GenericRef);
  982.             if Err = NoErr then
  983.                 Err := GetEOF(GenericRef, logicalEOF);
  984.             if (logicalEOF > 0) & (Err = NoErr) then
  985.                 begin
  986.                     Err := ReadALine(GenericRef, GenericPath);
  987.                     Err := FSClose(GenericRef);
  988.                     if ReadConfig then
  989.                         begin
  990.                             TReadMESSAGES;
  991.                             ProcessMSGHDR
  992.                         end
  993.                 end;
  994.  
  995.             TimeStamp;
  996.             Err := FSOpen(concat(gDefaultPath, 'Tabby:Tabby Log'), vRefNum, TLogRef);
  997.             Err := SetFPos(TLogRef, fsFromLEOF, 0);
  998.             if MsgCount > 0 then
  999.                 begin
  1000.                     if MsgCount = 1 then
  1001.                         TempString := concat(DateString, 'TExport - ', StringOf(MsgCount : GetWidth(MsgCount)), ' Message Total')
  1002.                     else
  1003.                         TempString := concat(DateString, 'TExport - ', StringOf(MsgCount : GetWidth(MsgCount)), ' Messages Total');
  1004.                     Err := WrLn(TLogRef, TempString);
  1005.                 end;
  1006.             Err := WrLn(TLogRef, concat(DateString, 'TExport - Program Ending'));
  1007.             Err := FSClose(TLogRef);
  1008.  
  1009.             DisposDialog(DialogPointer);
  1010.  
  1011.             if NextLaunch <> '' then
  1012.                 LaunchNextAppl
  1013.         end
  1014. end.